package com.tcoding.client.gui.main;

import com.jfoenix.assets.JFoenixResources;
import com.jfoenix.controls.JFXDecorator;
import com.jfoenix.controls.JFXProgressBar;
import com.tcoding.client.MainDemo;
import com.tcoding.client.bean.MenuVoCell;
import com.tcoding.client.request.Request;
import com.tcoding.client.request.feign.admin.MenuFeign;
import com.tcoding.client.request.feign.login.LoginFeign;
import com.tcoding.client.utils.AlertUtil;
import com.tcoding.client.websocket.WSClient;
import com.tcoding.core.msg.ObjectRestResponse;
import com.tcoding.core.util.EncryptUtil;
import com.tcoding.core.util.user.JwtAuthenticationRequest;
import io.datafx.controller.ViewConfiguration;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.Flow;
import io.datafx.controller.flow.FlowException;
import io.datafx.controller.flow.FlowHandler;
import io.datafx.controller.flow.action.ActionMethod;
import io.datafx.controller.flow.action.ActionTrigger;
import io.datafx.controller.flow.container.DefaultFlowContainer;
import io.datafx.controller.flow.context.ActionHandler;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.FlowActionHandler;
import io.datafx.controller.flow.context.ViewFlowContext;
import io.datafx.core.concurrent.ProcessChain;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import com.tcoding.core.vo.FrontUser;
import com.tcoding.core.vo.MenuVO;
import com.tcoding.core.vo.PermissionInfo;
import com.tcoding.client.store.ApplicationStore;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;
import java.net.URL;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

/**
 * @author 唐全成
 * @Date: 2022/5/30 14:37
 * @description
 **/
@Slf4j
@ViewController(value = "/fxml/login.fxml",title = "登录")
public class LoginController implements Initializable{
    @ActionHandler
    private FlowActionHandler actionHandler;
    @FXML
    private StackPane rootPane;
    @FXML
    private TextField userNameTextField;
    @FXML
    private PasswordField passWordTextField;
    @FXML
    @ActionTrigger("login")
    private Button loginButton;
    @FXML
    private JFXProgressBar progress1;
    @FXML
    private Label errorCodeLabel;

    @FXMLViewFlowContext
    private ViewFlowContext flowContext;

    @FXML
    private Label closeLogin;
    @PostConstruct
    public void init() throws Exception{
        progress1.visibleProperty().bind(rootPane.disableProperty());
        closeLogin.setOnMouseClicked(e->{
            Stage window =(Stage) rootPane.getScene().getWindow();
            window.close();
        });
    }
    @ActionMethod("login")
    public void login() {
        Stage window = (Stage) rootPane.getScene().getWindow();
        flowContext.register("LoginPane",window);
        JwtAuthenticationRequest jwtAuthenticationRequest = new JwtAuthenticationRequest();
        jwtAuthenticationRequest.setUsername(userNameTextField.getText());
        jwtAuthenticationRequest.setPassword(EncryptUtil.getInstance().Base64Encode(passWordTextField.getText()));
        ProcessChain.create()
                .addRunnableInPlatformThread(() -> {
                    rootPane.setDisable(true);
                    loginButton.setText("正在登录...");
                })
                .addSupplierInExecutor(() -> {
                    ObjectRestResponse<String> rel = Request.connector(LoginFeign.class).login(jwtAuthenticationRequest);
                    if (rel.getStatus() == 200) {
                        WSClient.getInstance().addHeader("Authorization", rel.getData());
                        WSClient.getInstance().addHeader("userName", userNameTextField.getText());
                    }
                    return rel;
                })
                .addConsumerInPlatformThread(rel -> {

                    if (rel.getStatus() == 200) {
                        errorCodeLabel.setText("");
                        ApplicationStore.setToken(rel.getData());
                        loadApplicatonStore();
                    } else {
                        progress1.requestFocus();
                        errorCodeLabel.setText(rel.getMessage());
                    }

                })
                .onException(e -> {
                    e.printStackTrace();
                    log.error("登录异常：{}",e.getMessage());
                    errorCodeLabel.setText("无法连接服务器，请检查服务器是否启动。");
                    progress1.requestFocus();
                })
                .withFinal(() -> {
                    rootPane.setDisable(false);
                    loginButton.setText("登录");
                }).run();


    }

    public void loadApplicatonStore() {
        ProcessChain.create()
                .addRunnableInPlatformThread(() -> {
                    try {
                        actionHandler.navigate(LoadingController.class);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    ApplicationStore.setName("");
                    ApplicationStore.getAllMenu().clear();
                    ApplicationStore.getMenus().clear();
                    ApplicationStore.getElements().clear();
                    ApplicationStore.getPermissionMenus().clear();
                    ApplicationStore.getRoles().clear();
                })
                .addSupplierInExecutor(() -> Request.connector(MenuFeign.class).getMenuAll())
                .addConsumerInPlatformThread(rel -> ApplicationStore.getAllMenu().addAll(rel))
                .addSupplierInExecutor(() ->
                        Request.connector(LoginFeign.class).getInfo(ApplicationStore.getToken())
                )
                .addConsumerInPlatformThread(rel -> {
                    if (rel.getStatus() == 200) {
                        FrontUser frontUser = rel.getData();
                        ApplicationStore.setName(frontUser.name);
                        ApplicationStore.setAvatar(frontUser.getAvatar());
                        ApplicationStore.getMenus().addAll(frontUser.getMenus());
                        ApplicationStore.getRoles().addAll(frontUser.getRoles());
                        ApplicationStore.getElements().addAll(frontUser.getElements());
                        ApplicationStore.setIntroduction(frontUser.getDescription());

                        for (PermissionInfo permissionInfo : frontUser.getElements()) {
                            ApplicationStore.getFeatureMap().put(permissionInfo.getCode(), permissionInfo.getName());
                        }


                    } else {
                        AlertUtil.show(rel);
                    }
                })
                .addSupplierInExecutor(() ->
                        Request.connector(LoginFeign.class).getMenus(ApplicationStore.getToken())
                )
                .addConsumerInPlatformThread(rel -> {
                    ApplicationStore.getPermissionMenus().addAll(rel);


                })
                .addSupplierInExecutor(() -> {

                    List<MenuVO> allMenuList = ApplicationStore.getAllMenu();
                    Map<Integer, List<MenuVO>> allMap = allMenuList.stream().collect(Collectors.groupingBy(MenuVO::getParentId));
                    MenuVO rootMenu = allMenuList.stream().min(Comparator.comparing(MenuVO::getParentId)).get();


                    List<MenuVO> permissionInfoList = ApplicationStore.getPermissionMenus();
                    Map<Integer, List<MenuVO>> permissionInfoMap = permissionInfoList.stream().collect(Collectors.groupingBy(MenuVO::getParentId));
                    Map<String, List<MenuVO>> permissonTitleMap = permissionInfoList.stream().collect(Collectors.groupingBy(MenuVO::getTitle));

                    for (MenuVO menu : allMap.get(rootMenu.getId())) {

                        List<MenuVO> childrenMenus = permissionInfoMap.get(menu.getId());

                        List<MenuVO> partMenus = permissonTitleMap.get(menu.getTitle());
                        if (childrenMenus == null && partMenus == null) {

                            continue;
                        }

                        MenuVoCell menuVoCell = new MenuVoCell(menu, childrenMenus);

                        ApplicationStore.getMenuVoCells().add(menuVoCell);

                    }
                    return 0;

                })
                .addConsumerInPlatformThread(rel -> {

                    try {
//                        actionHandler.navigate(MainController.class);
                        openMainInNewWindow();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }).addConsumerInPlatformThread(rel->{
                    WSClient.getInstance().connect();
                })
                .onException(e -> {
                    e.printStackTrace();
                    try {
                        actionHandler.navigate(LoginController.class);
                    } catch (Exception flowException) {
                        flowException.printStackTrace();
                    }
                })
                .run();
    }

    /**
     * Called to initialize a controller after its root element has been
     * completely processed.
     *
     * @param location  The location used to resolve relative paths for the root object, or
     *                  <tt>null</tt> if the location is not known.
     * @param resources The resources used to localize the root object, or <tt>null</tt> if
     */
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println(resources.getBaseBundleName());
    }

    private void openMainInNewWindow() throws FlowException {
        ViewConfiguration configuration = new ViewConfiguration();
        ResourceBundle bundle = ResourceBundle.getBundle("local/language");
        ApplicationStore.setResourceBundle(bundle);
        configuration.setResources(bundle);
        Flow flow = new Flow(MainController.class);
        DefaultFlowContainer container = new DefaultFlowContainer();
        Stage stage = new Stage();
//        stage.setAlwaysOnTop(true);
        Stage loginPane =(Stage) flowContext.getRegisteredObject("LoginPane");

        flowContext.register("MainStage", stage);

        FlowHandler handler = new FlowHandler(flow, new ViewFlowContext(), configuration);
        handler.start(container);
        JFXDecorator decorator = new JFXDecorator(stage, container.getView());
        ImageView imageView = new ImageView(new Image(this.getClass().getResourceAsStream("/images/code.png")));
        imageView.setFitWidth(32);
        imageView.setFitHeight(32);
        decorator.setGraphic(imageView);
        decorator.setCustomMaximize(true);
        stage.setTitle("HD_TECH_JFX");

        double width = 800;
        double height = 600;
        try {
            Rectangle2D bounds = Screen.getScreens().get(0).getBounds();
            width = bounds.getWidth()/1.2;
            height = bounds.getHeight()/1.2;
        }catch (Exception e){ }

        StackPane contentPane = new StackPane();
        contentPane.setPrefWidth(300);
        contentPane.setPrefHeight(4);
        JFXProgressBar progressBar = new JFXProgressBar();
        progressBar.prefWidthProperty().bind(stage.widthProperty());
        contentPane.getStyleClass().add("top-content");
        contentPane.getChildren().add(progressBar);
        decorator.getChildren().add(contentPane);
        progressBar.getStyleClass().add("top-content");
        progressBar.setVisible(false);
        ApplicationStore.setProgressBar(progressBar);

        flowContext.register("mainProgress",progressBar);

        Scene scene = new Scene(decorator, width, height);
        final ObservableList<String> stylesheets = scene.getStylesheets();
        stylesheets.addAll(
                JFoenixResources.load("css/jfoenix-design.css").toExternalForm(),
                MainDemo.class.getResource("/css/chenfei/color.css").toExternalForm(),
                MainDemo.class.getResource("/css/chenfei/core.css").toExternalForm(),
                MainDemo.class.getResource("/css/controlsfx.css").toExternalForm(),
                MainDemo.class.getResource("/css/theme/jfoenix-main-dark.css").toExternalForm()
        );

        stage.setScene(scene);
        stage.getIcons().add(new Image(this.getClass().getResourceAsStream("/images/code.png")));
        stage.initStyle(StageStyle.UNDECORATED);
        if(loginPane!=null){
            loginPane.close();
        }
        stage.show();
        //监听快捷键监听
        MainDemo.initShortKey(scene);
    }
}
